#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
 
#include "data_type.h"
#include "alloc.h"
#include "memfunc.h"
#include "basefunc.h"
#include "struct_deal.h"
#include "crypto_func.h"
#include "memdb.h"
#include "message.h"
#include "return_value.h"
#include "ex_module.h"
#include "sys_func.h"
#include "whitelist_hacker.h"
#include "tcm_constants.h"
#include "tcm_structures.h"
#include "tcm_key_manage.h"
#include "tcm_key_desc.h"
#include "tcm_pik_desc.h"
#include "system_entity.h"
#include "integrity_measure.h"

// add para lib_include
BYTE Buf[DIGEST_SIZE*16];

char ** compare_name={"cube-1.3","cube_tcmplugin","cube-whitelist",NULL};

int rand_err[4][4]= {{2,3,1,0},{1,3,0,2},{0,2,1,3},{3,1,2,0}};

char faultflag[3][64];

char RandBuf[9][DIGEST_SIZE*3];

int RandPcr[3][DIGEST_SIZE];


int count[4]={0,0,0,0};

int whitelist_hacker_init(void * sub_proc, void * para)
{
	int ret;
	int i;
	// add rand err 
	BYTE digest[DIGEST_SIZE];
	int pcrbuf[DIGEST_SIZE*2];

	RAND_bytes(digest,DIGEST_SIZE);

	digest_to_uuid(digest,Buf);
	Memcpy(faultflag[0],"flag{",5);
	Memcpy(faultflag[0]+5,Buf,32); 
	Memcpy(faultflag[0]+37,"}",2); 
	
	Memcpy(faultflag[1],"flag{",5);
	Memcpy(faultflag[1]+5,Buf+32,32); 
	Memcpy(faultflag[1]+37,"}",2); 

	RAND_bytes(digest,DIGEST_SIZE);

	digest_to_uuid(digest,Buf);
	Memcpy(faultflag[2],"flag{",5);
	Memcpy(faultflag[2]+5,Buf,32); 
	Memcpy(faultflag[2]+37,"}",2); 


	Memset(Buf,0,DIGEST_SIZE);
	for(i=0;i<9;i++)
	{
		RAND_bytes(RandBuf[i],DIGEST_SIZE*2);
		calculate_context_sm3(RandBuf[i],DIGEST_SIZE*2,RandBuf[i]+DIGEST_SIZE*2);
		if(i%3==0)
			Memset(pcrbuf,0,DIGEST_SIZE*2);
		Memcpy(pcrbuf+DIGEST_SIZE,RandBuf[i]+DIGEST_SIZE*2,DIGEST_SIZE);
		calculate_context_sm3(pcrbuf,DIGEST_SIZE*2,RandBuf[i]+DIGEST_SIZE*3);
		Memcpy(pcrbuf,RandBuf[i]+DIGEST_SIZE*3,DIGEST_SIZE);
		if(i%3==2)
			Memcpy(RandPcr[i/3],RandBuf[i]+DIGEST_SIZE*3,DIGEST_SIZE);
	}
	return 0;
}

int whitelist_hacker_start(void * sub_proc, void * para)
{
	int ret;
	void * recv_msg;
	int type;
	int subtype;
	// add yorself's module exec func here
	while(1)
	{
		usleep(time_val.tv_usec);
		ret=ex_module_recvmsg(sub_proc,&recv_msg);
		if(ret<0)
			continue;
		if(recv_msg==NULL)
			continue;
		type=message_get_type(recv_msg);
		subtype=message_get_subtype(recv_msg);
		if(!memdb_find_recordtype(type,subtype))
		{
			printf("message format (%d %d) is not registered!\n",
			message_get_type(recv_msg),message_get_subtype(recv_msg));
			continue;
		}
		if((type==TYPE(INTEGRITY_COLLECT))&&(subtype==SUBTYPE(INTEGRITY_COLLECT,UNITSET_MEASURE)))
		{
			ret=proc_whitelist_hacker(sub_proc,recv_msg);
		}
		else if((type==TYPE(TCM_PIK_DESC))&&(subtype==SUBTYPE(TCM_PIK_DESC,PCRQUOTE)))
		{
			ret=proc_report_hacker(sub_proc,recv_msg);
		}
	}
	return 0;
}

int proc_whitelist_hacker(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(INTEGRITY_COLLECT,UNITSET_MEASURE) * measure_value;
	void * send_msg;

	int i=0;

	ret=message_get_record(recv_msg,&measure_value,0);
	if(ret<0)
		return ret;

	int seq=0;
	if(measure_value->describe[4]=='{')
	{
		seq=0;
	}
	else if(measure_value->describe[11]=='}')
	{
		seq=2;
	}
	else 
	{
		seq=1;
	}

	int ifmodify=rand_err[seq][count[seq]%4];
	
	if(ifmodify !=0)
	{
		Memcpy(measure_value->measure_value,RandBuf[seq],DIGEST_SIZE*2);
		Memcpy(measure_value->uuid,RandBuf[seq]+DIGEST_SIZE*2,DIGEST_SIZE);
		Memcpy(measure_value->describe,faultflag[ifmodify]+seq*13,13);
		send_msg=message_create(TYPE_PAIR(INTEGRITY_COLLECT,UNITSET_MEASURE),recv_msg);
		if(send_msg==NULL)
			return -EINVAL;
		message_add_record(send_msg,measure_value);
		ex_module_sendmsg(sub_proc,send_msg);	
	}
	else
		ex_module_sendmsg(sub_proc,recv_msg);	
	return ret;
}

int proc_report_hacker(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(TCM_PIK_DESC,PCRQUOTE) * pcrquote;
	void * send_msg;

	ret=message_get_record(recv_msg,&pcrquote,0);
	if(ret<0)
		return -EINVAL;
	if(pcrquote==NULL)
		return -EINVAL;

	int seq=3;
	int ifmodify=rand_err[seq][count[seq]%4];
	
	if(ifmodify !=0)
	{
		Memcpy(pcrquote->pcrComp.pcrValue,RandPcr[ifmodify],DIGEST_SIZE);
		send_msg=message_create(TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE),recv_msg);
		if(send_msg==NULL)
			return -EINVAL;
		message_add_record(send_msg,pcrquote);
		ex_module_sendmsg(sub_proc,send_msg);	
	}
	else
		ex_module_sendmsg(sub_proc,recv_msg);	
	return ret;
}
